package com.hxs.hxsserver.service.impl;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hxs.hxsserver.config.redis.RedisService;
import com.hxs.hxsserver.config.redis.UserKey;
import com.hxs.hxsserver.domain.dto.IdDTO;
import com.hxs.hxsserver.domain.dto.PageBaseDto;
import com.hxs.hxsserver.domain.dto.ResponseCode;
import com.hxs.hxsserver.domain.dto.device.*;
import com.hxs.hxsserver.domain.entity.device.Device;
import com.hxs.hxsserver.domain.entity.device.DeviceFolder;
import com.hxs.hxsserver.domain.entity.device.DeviceStatusHistory;
import com.hxs.hxsserver.domain.entity.device.FactorHistory;
import com.hxs.hxsserver.domain.entity.user.User;
import com.hxs.hxsserver.exception.ApiException;
import com.hxs.hxsserver.mapper.device.DeviceFolderMapper;
import com.hxs.hxsserver.mapper.device.DeviceMapper;
import com.hxs.hxsserver.mapper.device.DeviceStatusHistoryMapper;
import com.hxs.hxsserver.mapper.device.FactorHistoryMapper;
import com.hxs.hxsserver.mapper.user.UserMapper;
import com.hxs.hxsserver.service.DeviceService;
import com.hxs.hxsserver.service.UserService;
import com.hxs.hxsserver.socketServer.SocketServer;
import com.hxs.hxsserver.utils.DozerUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;


/**
 * @author liuchuan
 * @create 2024/9/26
 */
@Service
@Slf4j
public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> implements DeviceService {

    @Resource
    private DozerUtil dozerUtil;
    @Resource
    private DeviceMapper deviceMapper;
    @Resource
    private DeviceFolderMapper deviceFolderMapper;
    @Resource
    private DeviceStatusHistoryMapper deviceStatusHistoryMapper;
    @Resource
    private FactorHistoryMapper factorHistoryMapper;
    @Resource
    SocketServer socketServer;
    @Resource
    UserService userService;
    @Resource
    private UserMapper userMapper;
    @Resource
    RedisService redisService;


    @Override
    public void insertDevice(Device device) {
        deviceMapper.insert(device);
    }

    @Override
    public void updateDevice(Device device) {
        LambdaUpdateWrapper<Device> updateWrapper = Wrappers.lambdaUpdate();
        updateWrapper.eq(Device::getId, device.getId());
        updateWrapper.set(Device::getDeviceIpAddr, device.getDeviceIpAddr());
        updateWrapper.set(Device::getDeviceStatus, device.getDeviceStatus());
        deviceMapper.update(null, updateWrapper);
    }

    @Override
    public IPage<DeviceDTO> getDeviceList(DeviceListQueryDTO deviceListQueryDTO, User user) {
        int layer =0;
        if(deviceListQueryDTO.getType()==null){
            deviceListQueryDTO.setType(1);
        }
        if(deviceListQueryDTO.getId()==null){
            deviceListQueryDTO.setId(user.getFolderId().toString());
        }
        if (deviceListQueryDTO.getType()==1){
            DeviceFolder deviceFolder = deviceFolderMapper.selectById(deviceListQueryDTO);
            layer = deviceFolder.getLayer();
        }
        LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.select(User::getId);
        List<Integer> usersId = null;
//        if (user.getRoleId() == 2 || user.getRoleId() == 3) {
//            lambdaQueryWrapper.eq(User::getParentId, user.getId());
//            usersId = userMapper.selectList(lambdaQueryWrapper)
//                    .stream()
//                    .map(User::getId)
//                    .collect(Collectors.toList());
//            usersId.add(user.getId());
//        }
        Page<Device> page = new Page<>(deviceListQueryDTO.getPage(), deviceListQueryDTO.getSize());
        IPage<DeviceDTO> deviceDTOIPage = deviceMapper.getDeviceListByUserId(page,deviceListQueryDTO,layer,usersId);
        return deviceDTOIPage;
    }

    @Override
    public Boolean updateDeviceById(DeviceDTO dto) {
        this.baseMapper.updateById(dozerUtil.map(dto, Device.class));
        return true;
    }

    @Override
    public Boolean insertDeviceById(DeviceDTO dto,User user) {
        dto.setUserId(user.getId());
        LambdaQueryWrapper<Device> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Device::getDeviceHardwareAddr, dto.getDeviceHardwareAddr());
        queryWrapper.eq(Device::getIsDelete, 0);
        Device device = baseMapper.selectOne(queryWrapper);
        if(device!=null){
            throw new ApiException(ResponseCode.DEVIEC_EXISTS_ERROR.getCode(), ResponseCode.DEVIEC_EXISTS_ERROR.getDesc());
        }
        if(dto.getAlarmUserId()==null){
            dto.setAlarmUserId(user.getId());
        }
        this.baseMapper.insert(dozerUtil.map(dto, Device.class));
        redisService.set(UserKey.deviceAddr,dto.getDeviceHardwareAddr(),dto.getDeviceHardwareAddr());
        return true;
    }

    @Override
    public Boolean deleteDeviceById(IdDTO idDTO) {
        LambdaQueryWrapper<Device> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Device::getId, idDTO.getId());
        Device device = baseMapper.selectById(idDTO.getId());

        LambdaUpdateWrapper<Device> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(Device::getId, idDTO.getId());
        updateWrapper.set(Device::getIsDelete,1);
        baseMapper.update(null,updateWrapper);

        redisService.delete(UserKey.deviceAddr,device.getDeviceHardwareAddr());
        return true;
    }

    @Override
    public Boolean insertFolder(FolderDTO folderDTO,User user) {
        DeviceFolder map = dozerUtil.map(folderDTO, DeviceFolder.class);
        map.setCreateUserId(user.getId());
        map.setId(null);
        LambdaQueryWrapper<DeviceFolder> deviceFolderLambdaQueryWrapper = new LambdaQueryWrapper<>();
        deviceFolderLambdaQueryWrapper.eq(DeviceFolder::getParentId, folderDTO.getParentId())
                .orderByDesc(DeviceFolder::getLayer) // 按 layer 降序排序
                .last("LIMIT 1");
        DeviceFolder deviceFolder = deviceFolderMapper.selectOne(deviceFolderLambdaQueryWrapper);
        if(deviceFolder!=null){
            map.setLayer(deviceFolder.getLayer()+1);
        }else {
            DeviceFolder deviceFolder1 = deviceFolderMapper.selectById(folderDTO.getParentId());
            map.setLayer(deviceFolder1.getLayer()*1000+101);
        }
        // 插入新文件夹
        deviceFolderMapper.insert(map);
        return true;
    }



    @Override
    public Boolean updateFolder(FolderDTO folderDTO) {
        DeviceFolder deviceFolder = dozerUtil.map(folderDTO, DeviceFolder.class);

        LambdaUpdateWrapper<DeviceFolder> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(DeviceFolder::getId, deviceFolder.getId());
        updateWrapper.set(DeviceFolder::getFolderName,deviceFolder.getFolderName());
        if(deviceFolder.getParentId()!=null){
            updateWrapper.set(DeviceFolder::getParentId,deviceFolder.getParentId());
        }
//        deviceFolderMapper.updateById(dozerUtil.map(folderDTO, DeviceFolder.class));
        deviceFolderMapper.update(null,updateWrapper);
        return true;
    }

    @Override
    @Transactional
    public Boolean deleteFolder(IdDTO idDTO) {
        DeviceFolder deviceFolder = deviceFolderMapper.selectById(idDTO.getId());
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getFolderId,idDTO.getId());
        queryWrapper.eq(User::getIsDelete,0);
        List<User> users = userMapper.selectList(queryWrapper);
        if(users.size()>0 && String.valueOf(deviceFolder.getLayer()).length()==6){
            throw new ApiException(ResponseCode.FOLDER_USER_ERROR.getCode(), ResponseCode.FOLDER_USER_ERROR.getDesc());
        }

        //把当前文件下的所有设备归属到当前父级去
        LambdaQueryWrapper<DeviceFolder> queryWrapper2 = new LambdaQueryWrapper<>();
        queryWrapper2.likeRight(DeviceFolder::getLayer, deviceFolder.getLayer());
        List<Integer> collect= deviceFolderMapper.selectList(queryWrapper2).stream()
                .map(DeviceFolder::getId)
                .collect(Collectors.toList());
        if(collect.size()>0){
            LambdaUpdateWrapper<Device> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.in(Device::getFolderId,collect);
            updateWrapper.set(Device::getFolderId, deviceFolder.getParentId());
            baseMapper.update(null,updateWrapper);
        }
        LambdaQueryWrapper<DeviceFolder> deviceFolderLambdaQueryWrapper = new LambdaQueryWrapper<>();
        deviceFolderLambdaQueryWrapper.eq(DeviceFolder::getLayer,deviceFolder.getLayer());
        //删除该文件夹及下属文件夹
        deviceFolderMapper.delete(deviceFolderLambdaQueryWrapper);
        return true;
    }

    @Override
    public DeviceDTO getDeviceById(IdDTO idDTO) {
        Device device = this.getById(idDTO.getId());
        return dozerUtil.map(device, DeviceDTO.class);
    }

    @Override
    public List<DeviceFolderTree> getDeviceTree(User user) {
        List<DeviceFolderTree> list = new ArrayList<>();
        LambdaQueryWrapper<Device> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Device::getIsDelete,0);
        if (user.getRoleId() == 2 || user.getRoleId() == 3) {
            queryWrapper.eq(Device::getFolderId,user.getFolderId());
        }
        List<Device> devices = deviceMapper.selectList(queryWrapper);

        for (Device device:devices){
            DeviceFolderTree deviceFolderTree = new DeviceFolderTree();
            deviceFolderTree.setId(device.getDeviceHardwareAddr());
            deviceFolderTree.setType(0);
            deviceFolderTree.setName(device.getDeviceName());
            deviceFolderTree.setParentId(String.valueOf(device.getFolderId()));
            deviceFolderTree.setDeviceStatus(device.getDeviceStatus());
            deviceFolderTree.setDeviceId(device.getId());
            list.add(deviceFolderTree);
        }

        LambdaQueryWrapper<DeviceFolder> queryWrapper1 = new LambdaQueryWrapper<>();
        if (user.getRoleId() == 2 || user.getRoleId() == 3) {
            DeviceFolder deviceFolder = deviceFolderMapper.selectById(user.getFolderId());
            queryWrapper1.likeRight(DeviceFolder::getLayer,deviceFolder.getLayer());
        }
        List<DeviceFolder> deviceFolders = deviceFolderMapper.selectList(queryWrapper1);

        for (DeviceFolder folder:deviceFolders){
            DeviceFolderTree deviceFolderTree = new DeviceFolderTree();
            deviceFolderTree.setId(String.valueOf(folder.getId()));
            deviceFolderTree.setType(1);
            deviceFolderTree.setName(folder.getFolderName());
            deviceFolderTree.setParentId(String.valueOf(folder.getParentId()));
            deviceFolderTree.setLayer(folder.getLayer());
            list.add(deviceFolderTree);
        }
        return list;
    }

    @Override
    public IPage<DeviceStatusHistory> getDeviceStatusHisList(DeviceStatusQueryDTO deviceListQueryDTO) {
        Page<DeviceStatusHistory> page = new Page<>(deviceListQueryDTO.getPage(), deviceListQueryDTO.getSize());
        IPage<DeviceStatusHistory> deviceDTOIPage = deviceStatusHistoryMapper.getDeviceStatusHisList(page,deviceListQueryDTO);
        return deviceDTOIPage;
    }

    @Override
    public RutrunDeviceNumDTO getDeviceNum(User user) {
//        List<Integer> usersId = userService.getUsersId(user);
        RutrunDeviceNumDTO rutrunDeviceNumDTO = new RutrunDeviceNumDTO();

        DeviceListQueryDTO deviceListQueryDTO = new DeviceListQueryDTO();
        deviceListQueryDTO.setType(1);
        deviceListQueryDTO.setId(user.getFolderId().toString());
        deviceListQueryDTO.setPage(1);
        deviceListQueryDTO.setSize(3000);
        DeviceFolder deviceFolder = deviceFolderMapper.selectById(deviceListQueryDTO);
        int layer = deviceFolder.getLayer();

        Page<Device> page = new Page<>(deviceListQueryDTO.getPage(), deviceListQueryDTO.getSize());
        IPage<DeviceDTO> deviceDTOIPage = deviceMapper.getDeviceListByUserId(page,deviceListQueryDTO,layer,null);
        List<DeviceDTO> records = deviceDTOIPage.getRecords();
        // 查询总数
        rutrunDeviceNumDTO.setTotal(records.size());
        List<DeviceDTO> onlineDevices = records.stream()
                .filter(device -> device.getDeviceStatus() == 1)
                .collect(Collectors.toList());
        // 查询在线数
        rutrunDeviceNumDTO.setOnlineNum(onlineDevices.size());
        // 查询离线数
        List<DeviceDTO> offDevices = records.stream()
                .filter(device -> device.getDeviceStatus() == 0)
                .collect(Collectors.toList());
        rutrunDeviceNumDTO.setOfflineNum(offDevices.size());
        return rutrunDeviceNumDTO;
    }

    @Override
    public void executeTask() {
        // 查询所有有效设备
        LambdaQueryWrapper<Device> deviceQueryWrapper = new LambdaQueryWrapper<>();
        deviceQueryWrapper.eq(Device::getIsDelete, 0)
                .eq(Device::getDeviceStatus, 1);
        List<Device> devices = deviceMapper.selectList(deviceQueryWrapper);

        devices.forEach(device -> {
            // 获取当前时间
            LocalDateTime currentTime = LocalDateTime.now();

            // 获取离线间隔
            Integer offline = device.getOfflineJudgmentInterval() * 60;

            //查询心跳记录
            DeviceStatusHistory deviceStatusHistory = getLatestDeviceStatusHistory(device.getDeviceHardwareAddr());
            if (deviceStatusHistory != null) {
                Date createTime = deviceStatusHistory.getCreateTime();
                // 将 Date 转换为 LocalDateTime
                LocalDateTime createLocalDateTime = createTime.toInstant()
                        .atZone(ZoneId.systemDefault())
                        .toLocalDateTime();
                // 将 设备上线时间 加上 离线间隔时间与当前时间做判断
                LocalDateTime timePlusSeconds = createLocalDateTime.plusSeconds(offline);
                //为true说明刚上线，跳过这次循环，为false则去检查历史表数据
                if(timePlusSeconds.isAfter(currentTime)){
                    return;
                }
                // 检查最新的 FactorHistory 数据
                FactorHistory latestFactorHistory = getLatestFactorHistory(device.getDeviceHardwareAddr());
                if (latestFactorHistory != null) {
                    // 如果有最新的历史记录
                    LocalDateTime createLocalDateTime1 = latestFactorHistory.getCreateTime().toInstant()
                            .atZone(ZoneId.systemDefault())
                            .toLocalDateTime().plusSeconds(offline);
                    // 判断是否需要更新设备状态  如果最新的数据加上离线间隔时间后再当前时间之前则更新设备为离线状态
                    if(createLocalDateTime1.isBefore(currentTime)){
                        updateDeviceStatusToOffline(device);
                    }
                }
            }

        });
    }

    // 获取最新的 FactorHistory 数据
    private FactorHistory getLatestFactorHistory(String hardwareAddr) {
        LambdaQueryWrapper<FactorHistory> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(FactorHistory::getDeviceHardwareAddr, hardwareAddr)
                .orderByDesc(FactorHistory::getCreateTime)
                .last("LIMIT 1");
        return factorHistoryMapper.selectOne(queryWrapper);
    }

    // 获取最新的 DeviceStatusHistory 数据
    private DeviceStatusHistory getLatestDeviceStatusHistory(String hardwareAddr) {
        LambdaQueryWrapper<DeviceStatusHistory> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DeviceStatusHistory::getDeviceHardwareAddr, hardwareAddr);
        queryWrapper.eq(DeviceStatusHistory::getStatus, 1).orderByDesc(DeviceStatusHistory::getCreateTime)
                .last("LIMIT 1");
        return deviceStatusHistoryMapper.selectOne(queryWrapper);
    }

    // 计算时间差（秒）
    private long calculateTimeDifference(Date createTimeDate, LocalDateTime currentTime) {
        LocalDateTime createTime = createTimeDate.toInstant()
                .atZone(ZoneId.systemDefault())
                .toLocalDateTime();
        Duration duration = Duration.between(createTime, currentTime);
        return duration.getSeconds();
    }

    // 更新设备状态为离线
    private void updateDeviceStatusToOffline(Device device) {
        device.setDeviceStatus(0);
        device.setLastOfflineTime(new Date());
        deviceMapper.updateById(device);

        // 添加历史记录
        DeviceStatusHistory deviceStatusHistory = new DeviceStatusHistory();
        deviceStatusHistory.setDeviceHardwareAddr(device.getDeviceHardwareAddr());
        deviceStatusHistory.setStatus(0);
        deviceStatusHistoryMapper.insert(deviceStatusHistory);

        // 清除客户端连接
        socketServer.closehandler(device.getDeviceHardwareAddr());
    }

}
